﻿#pragma once
#include <fmt/color.h>
#include <fmt/ostream.h>
#include <fmt/ranges.h>
#include <spdlog/spdlog.h>
#include <stdio.h>

#include <chrono>
#include <cstdint>
#include <iostream>
#include <string_view>
#include <tuple>


///0000000000000000000000000000000000000000000000000000000000000000000000000000000000000 print macros

/// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx print separators
// print newline
#define MY_C_PRT_NEWLINE printf("\n")
/// basic sep
inline void MySep() { std::cout << "======================"; }
inline void MySubSep() { std::cout << "--------------"; }
/// sep with newline
inline void MySepln() { printf("==================\n"); }
inline void MySubSepln() { printf("--------------\n"); }

/// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx format print
inline void MyMessage(std::string msg) { std::cout << "---- " << msg << "\n"; }

template <typename... Args>
auto MyPrint(Args&&... args) -> decltype(::fmt::print(std::forward<Args>(args)...))
{
    return fmt::print(std::forward<Args>(args)...);
}

/// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx print colors
/// raw console control sequences
#if 0
#    define MY_CLR_FG_BL (::std::cout << "\033[0m\033[1;36m");
#    define MY_CLR_FG_BL (printf("\033[0m\033[1;36m"))
#    define MY_CLR_FG_BL (printf("\033[0m\033[38;2;0;255;255m"))
#    define MY_CLR_FG_RESET (printf("\033[0m"))
#endif

///
#define MY_CLR_FG_BL_STRING "\033[0m\033[38;2;0;255;255m"
#define MY_CLR_FG_RESET_STRING "\033[0m"
#define MY_CLR_FG_BL (::std::cout << MY_CLR_FG_BL_STRING)
#define MY_CLR_FG_RESET (::std::cout << MY_CLR_FG_RESET_STRING)

//#define MY_FLUSH_STD_OUT_ std::fflush(stdout)
#define MY_FLUSH_STD_OUT_

/// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Logger macros
#define MYINFO(...) ::spdlog::info(__VA_ARGS__)
#define MYDEBUG(...) ::spdlog::debug(__VA_ARGS__)
#define MYWARN(...) ::spdlog::warn(__VA_ARGS__)
#define MYERROR(...) ::spdlog::error(__VA_ARGS__)

///
#define MY_SUBSEP                       \
    spdlog::info("------------------"); \
    MY_FLUSH_STD_OUT_;

#define MY_SEP_TEST                                       \
    spdlog::info("\nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); \
    MY_FLUSH_STD_OUT_;

#define MY_SEP                             \
    spdlog::info("====================="); \
    MY_FLUSH_STD_OUT_;

#define MY_NEWLINE    \
    spdlog::info(""); \
    MY_FLUSH_STD_OUT_;

/// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx print function path, variables
#define MY_ECHOFUNPATH                                                               \
    /* printf("Name: %s\n", __FUNCTION__); */                                        \
    /*::std::cout << "Name: " << __FUNCTION__ << " -------------" << ::std::endl; */ \
    spdlog::info("============================ Name: {}", __FUNCTION__);             \
    MY_FLUSH_STD_OUT_;

/// print variable
#define MY_ECHO(V) ::std::cout << #V " = " << V << "\n";
#define MY_ECHO2(M, V) ::std::cout << M " = " << V << "\n";

/// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx print raw array
template <typename T>
void MyPrtArr(const T* v, size_t cnt)
{
    if (cnt == 0)
    {
        MyPrint("[ ]");
        return;
    }
    MyPrint("[ ");
    for (size_t i = 0; i < cnt - 1; i++) MyFmtPrt("{}, ", v[i]);
    MyFmtPrt("{} ]", v[cnt - 1]);
}

//------------ print raw array with newline
template <typename T>
void MyPrtArrLn(const T* v, size_t cnt)
{
    MyPrtArr(v, cnt);
    MY_C_PRT_NEWLINE;
}

/// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx print ranges

/// iterators
template <typename T>
void MyPrtIters(::std::string_view name, T const& q)
{
    ::std::cout << name << ": \t";
    for (auto const& n : q) ::std::cout << n << ' ';
    MY_C_PRT_NEWLINE;
}

/// print std::queue
template <typename Q>
void MyPrtQueue(std::string_view name, Q q)
{
    // 注意：按值传递 q，这是因为无法在不清楚队列的情况下遍历 priority_queue 的内容。
    for (::std::cout << name << ":" << ::std::endl; !q.empty(); q.pop())
    {
        ::std::cout << q.top() << ' ';
    }
    MY_C_PRT_NEWLINE;
}

/// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx eigen format
#define MyEigenFormat Eigen::IOFormat _myEigenFmt(Eigen::StreamPrecision, 0, ", ", ";\n", "", "", "[", "]");

/// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 打印表达式的类型信息
template <typename T>
::std::string TypeToString()
{
#if defined(_MSC_VER)
    ::std::string type_name{__FUNCSIG__};
    // class ::std:: basic_string<char,struct ::std:: char_traits<char>,class ::std:: allocator<char> >
    //    __cdecl type_to_string<int&>(void)
    auto start_pos = type_name.find_first_of('<', ::std::string(typeid(::std::string).name()).size()) + 1;
    auto end_pos = type_name.find_last_of('>');
    return type_name.substr(start_pos, (end_pos - start_pos));
#elif defined(__clang__)
    ::std::string type_name{__PRETTY_FUNCTION__};
    auto start_pos = type_name.find_first_of('=') + 2;
    auto end_pos = type_name.find_first_of(']', start_pos);
    return type_name.substr(start_pos, (end_pos - start_pos));

#elif defined(__GNUC__)
    ::std::string type_name{__PRETTY_FUNCTION__};
    // ::std:: __cxx11::string type_to_string() [with T = int&; ::std:: __cxx11::string = ::std:: __cxx11::basic_string<char>]
    auto start_pos = type_name.find_first_of('=') + 2;
    auto end_pos = type_name.find_first_of(';', start_pos);
    return type_name.substr(start_pos, (end_pos - start_pos));
#endif
}

///0000000000000000000000000000000000000000000000000000000000000000000000000000000000000 平台兼容性宏

// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx platform
#define MY_PLTFM_UNKNOWN (static_assert(false, "unkown platform"));

// 处理不同平台和编译器的差异
#if defined(_WIN32) || defined(_WIN64)
#    define MY_PLTFM_WIN 1
#elif defined(__linux__)
#    define MY_PLTFM_LINUX 1
#endif

#if defined(__clang__)
#    define MY_CMPLER_LLVM 10
#else
#    define MY_CMPLER_LLVM 0
#endif

#if defined(_MSVC_LANG) && !defined(__clang__) /* && defined(_WIN32) && defined(_MSC_VER) */
#    define MY_CMPLER_MSVC 10
#else
#    define MY_CMPLER_MSVC 0
#endif

#if defined(__GNUC__) /* || defined(__GNUG__)*/
#    define MY_CMPLER_GCC 10
#else
#    define MY_CMPLER_GCC 0
#endif

#if defined(__APPLE__) && defined(__GNUC__) && !defined(__clang__)
#    define MY_CMPLER_MACGCC 1
#else
#    define MY_CMPLER_MACGCC 0
#endif

// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx function cross platform
#if MY_CMPLER_MSVC || MY_CMPLER_LLVM
#    define MY_C_REDUCE std::reduce
#elif MY_CMPLER_GCC || MY_CMPLER_MACGCC
#    define MY_C_REDUCE std::accumulate
#else
#    define MY_C_REDUCE MY_PLTFM_UNKNOWN
#endif

// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 如果在 msvc cl 环境, 使用特定的宏
#ifndef _MSVC_LANG
#    define __FUNCDNAME__ __PRETTY_FUNCTION__
#    define __FUNCSIG__ __PRETTY_FUNCTION__
#endif

///xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 函数签名 header
/// .h 中使用
#define MY_FIN_I8 inline int8_t
#define MY_FIN_I32 inline int32_t
#define MY_FIN_VOID inline void
/// .cpp, .cxx .cu 源文件中使用
#define MY_FN_I8 int8_t
#define MY_FN_I32 int32_t
#define MY_FN_VOID void

///xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 数学函数
#ifndef IMAX
#    define IMAX(a, b) (((a) > (b)) ? (a) : (b))
#endif

// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 测试用
//#define MYTEST(x) x // identity
#define MYPASS(x) ;  // 空语句

// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx machine endian 大端序, 小端序
/* 深入理解计算机系统 2.2.5
* data.n = 0xAB'CD'EF'01;
* 01 EF CD AB 小端序
* AB CD EF 01 大端序
*/
#define MY_PRT_LIT_OR_BIG_ENDIAN                         \
    ::std::ignore = []()                                 \
    {                                                    \
        union                                            \
        {                                                \
            unsigned n;                                  \
            char ch;                                     \
        } data;                                          \
        data.n = 0xAB'CD'EF'01;                          \
        if (data.ch == 0x01)                             \
        {                                                \
            MyfPrt("This machine is [Little-endian]\n"); \
        }                                                \
        else                                             \
        {                                                \
            MyfPrt("This machine is [Big-endian]\n");    \
        }                                                \
        return 0;                                        \
    }();

// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx cout, cin 加速
// https://www.zhihu.com/question/614285401/answer/3476754940
/*
* ios_base::sync_with_stdio(false)
* 这一行代码关闭了C++标准输入输出流与C标准库输入输出流的同步。
* 默认情况下，C++的输入输出流与C标准库的输入输出流是同步的，
* 这意味着每当使用C++的输入输出流时，都会同步刷新C标准库的缓冲区。
* 通过关闭同步，可以避免这种同步操作，从而提高输入输出的效率；
*
* cin.tie(nullptr):
* 这一行代码将C++标准输入流(cin)和C++标准输出流(cout)的绑定解除。
* 默认情况下，cin和cout是绑定在一起的，即在执行输入操作时，输出缓冲区会自动刷新。
* 通过解除绑定，可以避免这种自动刷新，提高输入操作的效率。
*/

#define MY_SPPEDUP_IOSTREM_CIN_COUT              \
    ::std::ignore = []()                         \
    {                                            \
        ::std::ios_base::sync_with_stdio(false); \
        ::std::cin.tie(nullptr);                 \
        return 0;                                \
    }();

//------------------------ Get Set Macro
#define SetMacro(name, type)         \
    inline void Set##name(type arg1) \
    {                                \
        if (this->name != arg1)      \
        {                            \
            this->name = arg1;       \
        }                            \
    }

#define SetMacroDirect(name, type) \
    inline void Set##name(type arg1) { this->name = arg1; }

#define GetMacro(name, type) \
    inline type Get##name() const { return this->name; }

//--------- virtual version

#define VirtualSetMacro(name, type)   \
    virtual void Set##name(type arg1) \
    {                                 \
        if (this->name != arg1)       \
        {                             \
            this->name = arg1;        \
        }                             \
    }

#define VirtualSetMacroOverride(name, type)    \
    virtual void Set##name(type arg1) override \
    {                                          \
        if (this->name != arg1)                \
        {                                      \
            this->name = arg1;                 \
        }                                      \
    }

#define VirtualGetMacro(name, type) \
    virtual type Get##name() const { return this->name; }

#define MYSize(x) ((ptrdiff_t)sizeof(x))
#define MYLen(a) (MYSize(a) / MYSize((a)[0]))
#define MYEnd(s) (MYLen(s) - 1)

///xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 简单计算运行时间
#define MY_TIMEIT_I                                               \
    ::std::chrono::steady_clock::time_point _my_start_, _my_end_; \
    double _my_duration_count_;
#define MY_TIMEIT_A _my_start_ = ::std::chrono::steady_clock::now(); /*开始时间*/
#define MY_TIMEIT_B                                                                                                         \
    _my_end_ = ::std::chrono::steady_clock::now(); /*结束时间*/                                                             \
    _my_duration_count_ = (double)::std::chrono::duration_cast<::std::chrono::milliseconds>(_my_end_ - _my_start_).count(); \
    MyfPrt(">>>Run time: {} ms\t==\t", _my_duration_count_);                                                                \
    _my_duration_count_ /= 1000.0;                                                                                          \
    MyfPrt("{} sec\n", _my_duration_count_);

///xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 调试和错误检查宏
/// 调试输出
#ifdef DEBUG
#    define MY_DBG_PRT(fmt, ...) printf("[DEBUG] %s:%d: " fmt, __FILE__, __LINE__, ##__VA_ARGS__)
#else
#    define MY_DBG_PRT(fmt, ...)
#endif